//
//	  LargeNumber.java
//
//	  Copyright (c) 2011 <John Lawniczak>
//	  jlawniczak340license@gmail.com
//
//    This file is part of CS102_Assignment3.
//
//    CS102_Assignment3 is free software: you can redistribute it and/or modify
//    it under the terms of the GNU General Public License as published by
//    the Free Software Foundation, version 3 of the License.
//
//    CS102_Assignment3 is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//    GNU General Public License for more details.
//
//    You should have received a copy of the GNU General Public License
//    along with CS102_Assignment3.  If not, see <http://www.gnu.org/licenses/>.
//
/**************************************************
Class Name: LargeNumber
Author's Name: John Lawniczak
Date: 05-19-2010
Description of the class: Stores data for a very large number in stacks and adds, and multiplies
***************************************/
public class LargeNumber {
	private Stack<Integer> numStack;

	/**************************************************
	Constructor
	Input to the method: String the input from the user to beparsed and turned into a largenumber
	Output(Return value): none  
	Author: John Lawniczak
	**************************************************/
	public LargeNumber(String strNum) throws IllegalArgumentException {
		numStack = new Stack<Integer>();
		char[] arryChars = strNum.toCharArray();

		for (int i = 0; i < arryChars.length; i++) {
			Character tmp = arryChars[i];
			if (tmp <= '9' && tmp >= '0') {
				numStack.push(Integer.parseInt(tmp.toString()));
			} else if (tmp == '.') {
				i = arryChars.length + 1;
			} else {
				throw new IllegalArgumentException();
			}
		}
	}
	/**************************************************
	Method Name: MultiplyByLargeNumber
	Input to the method: Element to multiply the this.num by
	Output(Return value): the product
	Brief description of the task: multiplys two large numbers
	Throws: IllegalArgumentException if the string is not correct  
	Author: John Lawniczak
	**************************************************/
	public LargeNumber MultiplyByLargeNumber(LargeNumber num2)
			throws IllegalArgumentException {
		LargeNumber sum = new LargeNumber("");
		LargeNumber tmp = new LargeNumber("");
		LargeNumber oldNum2 = new LargeNumber("");
		Integer firstFactor = new Integer(0), secondFactor = new Integer(0), product = new Integer(
				0), remainder = new Integer(0);
		int i = 0;
		while (!this.numStack.empty()) {
			
			firstFactor = this.numStack.pop();
			int j = 0;
			Integer carry = new Integer(0);
			tmp = addZeroes(i, tmp);
			
			while(!num2.numStack.empty()){
				secondFactor = num2.numStack.pop();
				oldNum2.numStack.push(secondFactor);
				product = new Integer((int) (secondFactor * firstFactor+carry));
				remainder = product%10;
				carry = product/10;
				tmp.numStack.push(remainder);
				j++;
			}
			
			if(num2.numStack.empty()&& carry !=0){
				tmp.numStack.push(new Integer(carry));
			}
			carry = 0;
			i++;
			tmp = this.reverse(tmp);
			sum = this.reverse(sum);
			//System.out.print(sum);
			sum = this.AddLargeNumber((sum), tmp);
			//System.out.println("tmp added: " + sum);
			while(!oldNum2.numStack.empty()){//reload the now empty num2 stack with the original contents
				num2.numStack.push(oldNum2.numStack.pop());
			}
		}
		return sum;
	}

	/**************************************************
	Method Name: addZeroes
	Input to the method: int i number of zeros to add, Largenumber to add zeros to 
	Output(Return value): the result of the operation
	Brief description of the task: adds zeros to the top of a stack
	Author: John Lawniczak
	**************************************************/
	private LargeNumber addZeroes(int i, LargeNumber num){
		for(int q=0; q<i; q++){
			num.numStack.push(new Integer(0));
		}
		return num;
	}
	
	/**************************************************
	Method Name: AddLargeNumber
	Input to the method: Two Large numbers to add 
	Output(Return value): the sum of the two large numbers as a LargeNumber
	Brief description of the task: adds two large numbers
	Author: John Lawniczak
	**************************************************/	
	public LargeNumber AddLargeNumber(LargeNumber num1, LargeNumber num2 ) {
		LargeNumber ret = new LargeNumber("");
		Integer carry = new Integer(0);
		while (!num2.numStack.empty() && !num1.numStack.empty()) {//TODO take care of the carry
			Integer sum = (num2.numStack.pop() + num1.numStack.pop());
			Integer toAdd = new Integer((sum%10+carry));
			ret.numStack.push(toAdd);
			carry = sum/10;
		}
		while(!num2.numStack.empty()){
			Integer popped = num2.numStack.pop();
			Integer toAdd = popped%10 + carry;
			ret.numStack.push(toAdd);
			carry = popped/10;
		}
		while(!num1.numStack.empty()){
			Integer popped = num1.numStack.pop();
			Integer toAdd = popped%10 + carry;
		 	ret.numStack.push(toAdd);
		 	carry = popped/10;
		}
		return ret;
	}
	/**************************************************
	Method Name: Reverse
	Input to the method: large number to reverse 
	Output(Return value): the reversed large number
	Brief description of the task: reverses a large number
	Author: John Lawniczak
	**************************************************/	
	public LargeNumber reverse(LargeNumber n) {
		LargeNumber ret = new LargeNumber("");
		while (!n.numStack.empty()) {
			ret.numStack.push(n.numStack.pop());
		}
		return ret;
	}
	
	/**************************************************
	Method Name: toString
	Input to the method:  none
	Output(Return value): The String representing the largenumber
	Brief description of the task: creates a string representing the large number
	Author: John Lawniczak
	**************************************************/	
	public String toString() {
		return numStack.toString();
	}
}
